package com.link.serve.tcp.handler;// 服务端 Handler
import com.link.serve.tcp.linkdata.SingleUserChannelManager;
import com.link.serve.tcp.process.factory.ProcessorFactory;
import com.link.serve.tcp.handler.tactics.impl.LoginDisconnectionHandler;
import com.link.serve.tcp.handler.tactics.impl.LoginHeartbeatTimeoutHandler;
import com.link.serve.tcp.message.Message;
import com.link.serve.tcp.message.proto.PackHeader;
import com.link.serve.tcp.process.AbstractMessageProcessor;
import com.link.serve.type.IMCmdType;
import com.link.serve.utils.SpringContextHolder;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Objects;


@SuppressWarnings("rawtypes")
@Slf4j
@Component
public class NettyServerHandler extends SimpleChannelInboundHandler<Message> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Message msg) throws Exception {
        PackHeader.Header header = msg.getHeader(); // 获取消息头

        AbstractMessageProcessor processor =
                ProcessorFactory// 利用工厂策略模式
                .createProcessor(//根据消息头的type创建不同处理器
                        Objects.requireNonNull(
                                IMCmdType.fromCode(
                                        header.getMessageType())));

        processor.process(ctx, processor.transForm(msg));
    }
    /**
     * 出现异常的处理 打印报错日志
     * @param ctx   channel上下文
     * @param cause 异常信息
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error("异常发生:{}", cause.getMessage());
    }

    /**
     * 监控浏览器上线
     * @param ctx channel上下文
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
//        log.info(ctx.channel().id().asLongText() + "连接");
    }

    /**
     * 当前用户主动下线或心跳机制失败触发
     * @param ctx
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) {
        //TODO：删除redis存储的用户与机器信息
        SpringContextHolder.getApplicationContext().getBean(LoginDisconnectionHandler.class).handleDisconnection(ctx);
    }
    /**
     *  心跳一定时间未收到，则触发删除本机
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleState state = ((IdleStateEvent) evt).state();
            if (state == IdleState.READER_IDLE) {
                //删除当前存在的channel信息
                SpringContextHolder
                        .getApplicationContext()
                        .getBean(LoginHeartbeatTimeoutHandler.class)
                        .handleTimeout(ctx);
                ctx.channel().close();
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }
}
